#include "i2c_v1.hpp"
#include <glog/logging.h>
// dev_path = "/dev/i2c-1"
i2c_v1::i2c_v1(const std::string dev_path, uint8_t device_address)
    : _dev_path(dev_path),
      _device_address(device_address)
{
    _flag = YJ_OFF;
    _fd = -1;
}

yj_return i2c_v1::open()
{
    if (_fd < 0)
        _fd = ::open(_dev_path.c_str(), O_RDWR);
    else
    {
        LOG(ERROR) << "⚠️ Already opened";
    }
    if (_fd < 0)
    {
        LOG(ERROR) << "❌ Open failed: " << strerror(errno);
        _flag = YJ_OFF;
        _fd = -1;
        return YJ_ERROR;
    }
    _flag = YJ_ON;

    if (set_address(_device_address) != YJ_OK)
    {
        LOG(ERROR) << "❌ Set address failed";
        return YJ_ERROR;
    }

    print_config();
    return YJ_OK;
}

i2c_v1::~i2c_v1()
{
    close();
}
void i2c_v1::close()
{
    if (_fd >= 0)
    {
        ::close(_fd);
        _fd = -1;
    }
}

// 设置地址（返回错误码）
yj_return i2c_v1::set_address(uint8_t address)
{
    if (_flag == YJ_OFF)
    {
        LOG(ERROR) << "❌ Open device first";
        return YJ_ERROR;
    }
    if (address > 127)
    {
        LOG(ERROR) << "❌ Address out of range,0x00~0x7F,address must be 7 bits";
        return YJ_ERROR;
    }

    if (ioctl(_fd, I2C_SLAVE, address) < 0)
    {
        LOG(ERROR) << "❌ Set address failed: " + std::string(strerror(errno));
        return YJ_ERROR;
    }
    _device_address = address;
    return YJ_OK;
}

// 写寄存器（返回布尔值）
yj_return i2c_v1::write_register(uint8_t reg, const uint8_t *data, uint16_t len)
{
    std::lock_guard<std::mutex> lock(_i2c_mutex);
    if (_flag == YJ_OFF)
    {
        LOG(ERROR) << "❌ Open device first";
        return YJ_ERROR;
    }

    uint8_t buffer[len + 1];
    buffer[0] = reg;
    memcpy(buffer + 1, data, len);

    if (write(_fd, buffer, len + 1) != static_cast<ssize_t>(len + 1))
    {
        LOG(ERROR) << "❌ Write failed: " + std::string(strerror(errno));
        return YJ_ERROR;
    }
    return YJ_OK;
    
}

// 读寄存器（返回布尔值）
yj_return i2c_v1::read_register(uint8_t reg, uint8_t *data, uint16_t len)
{
     std::lock_guard<std::mutex> lock(_i2c_mutex);
    if (_flag == YJ_OFF)
    {
        LOG(ERROR) << "❌ Open device first";
        return YJ_ERROR;
    }

    struct i2c_msg messages[2] =
        {
            {_device_address, 0, 1, &reg},         // 写寄存器地址
            {_device_address, I2C_M_RD, len, data} // 读数据
        };
    struct i2c_rdwr_ioctl_data ioctl_data = {messages, 2};
    if (ioctl(_fd, I2C_RDWR, &ioctl_data) < 0)
    {
        LOG(ERROR) << "❌ I2C_RDWR failed: " << strerror(errno);
        return YJ_ERROR;
    }
    return YJ_OK;
}

uint8_t i2c_v1::get_address()
{
    return _device_address;
}

yj_return i2c_v1::get_flag()
{
    return _flag;
}

yj_return i2c_v1::is_open()
{
    if (_flag == YJ_ON)
        return YJ_OK;
    return YJ_OFF;
}

std::string i2c_v1::get_dev_path()
{
    return _dev_path;
}

void i2c_v1::print_config()
{
    LOG(INFO) << " I2C device file: " << _dev_path;
    LOG(INFO) << " I2C device address: " << std::hex << std::setfill('0') << std::setw(2) << std::uppercase << static_cast<int>(_device_address);
}
